/**
 * 加密工具类
 * 提供AES和RSA加密方法，用于登录等需要加密的场景
 */

import CryptoJS from 'crypto-js';
import JSEncrypt from 'jsencrypt';

// RSA公钥，从环境变量或配置中获取，这里使用示例公钥
const PUBLIC_KEY = `-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC8HMr2CBpoZPm3t9tCVlrKtTmI
4jNJc7PpROkoxBYOHZvmOdiaKHQU9bTIwvnW1+mPm64HtCKvKAzGLmDMQHwYPPac
NFcvWDuQNnv7vNAwbKBWkz5NwOHwoYYQZXIQCZL63KcGzxt6DtkJ8dLQUUJLJVL5
iwPpQBa+iyp5pnWwEwIDAQAB
-----END PUBLIC KEY-----`;

/**
 * AES加密配置
 */
interface AESConfig {
  key: string | CryptoJS.lib.WordArray; // 加密密钥
  iv?: string | CryptoJS.lib.WordArray; // 初始化向量
  mode?: string; // 加密模式，默认ECB
  padding?: string; // 填充方式，默认Pkcs7
}

/**
 * 默认AES配置
 */
const DEFAULT_AES_CONFIG: AESConfig = {
  key: 'dromara-sa-token', // 修改为与后端一致的默认密钥
  mode: 'ECB', // 使用ECB模式
  padding: 'Pkcs7'
};

/**
 * 生成随机字符串
 * @param length 字符串长度，默认32位
 * @returns 随机字符串
 */
export function generateRandomString(length: number = 32): string {
  const characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
  let result = '';
  const charactersLength = characters.length;
  for (let i = 0; i < length; i++) {
    result += characters.charAt(Math.floor(Math.random() * charactersLength));
  }
  return result;
}

/**
 * 生成AES密钥
 * @returns WordArray格式的AES密钥
 */
export function generateAesKey(): CryptoJS.lib.WordArray {
  return CryptoJS.enc.Utf8.parse(generateRandomString(32));
}

/**
 * Base64编码
 * @param data 待编码数据
 * @returns Base64编码后的字符串
 */
export function encryptBase64(data: string | CryptoJS.lib.WordArray): string {
  if (typeof data === 'string') {
    return CryptoJS.enc.Base64.stringify(CryptoJS.enc.Utf8.parse(data));
  }
  return CryptoJS.enc.Base64.stringify(data);
}

/**
 * Base64解码
 * @param encodedData Base64编码的字符串
 * @returns 解码后的字符串
 */
export function decryptBase64(encodedData: string): string {
  return CryptoJS.enc.Base64.parse(encodedData).toString(CryptoJS.enc.Utf8);
}

/**
 * 使用RSA公钥加密数据
 * @param txt 要加密的文本
 * @returns 加密后的文本
 */
export function encryptWithRsa(txt: string): string {
  const encryptor = new JSEncrypt();
  encryptor.setPublicKey(PUBLIC_KEY);
  const encrypted = encryptor.encrypt(txt);
  return encrypted || '';
}

/**
 * 使用AES加密数据
 * @param data 待加密数据
 * @param key AES密钥(WordArray或字符串)
 * @param config 加密配置
 * @returns 加密后的字符串
 */
export function encryptWithAes(data: string, key: CryptoJS.lib.WordArray | string, config: Partial<AESConfig> = {}): string {
  const mergedConfig = { ...DEFAULT_AES_CONFIG, ...config, key };
  const { mode, padding } = mergedConfig;
  
  // 确保key是WordArray类型
  const keyHex = typeof key === 'string' ? CryptoJS.enc.Utf8.parse(key) : key;
  
  // 确定加密模式和填充方式
  const cryptMode = CryptoJS.mode[mode as keyof typeof CryptoJS.mode] || CryptoJS.mode.ECB;
  const cryptPadding = CryptoJS.pad[padding as keyof typeof CryptoJS.pad] || CryptoJS.pad.Pkcs7;
  
  // 执行加密
  const encrypted = CryptoJS.AES.encrypt(data, keyHex, {
    mode: cryptMode,
    padding: cryptPadding
  });
  
  return encrypted.toString();
}

/**
 * 使用AES解密数据
 * @param encryptedData 已加密数据
 * @param key AES密钥(WordArray或字符串)
 * @param config 解密配置
 * @returns 解密后的字符串
 */
export function decryptWithAes(encryptedData: string, key: CryptoJS.lib.WordArray | string, config: Partial<AESConfig> = {}): string {
  const mergedConfig = { ...DEFAULT_AES_CONFIG, ...config, key };
  const { mode, padding } = mergedConfig;
  
  // 确保key是WordArray类型
  const keyHex = typeof key === 'string' ? CryptoJS.enc.Utf8.parse(key) : key;
  
  // 确定解密模式和填充方式
  const cryptMode = CryptoJS.mode[mode as keyof typeof CryptoJS.mode] || CryptoJS.mode.ECB;
  const cryptPadding = CryptoJS.pad[padding as keyof typeof CryptoJS.pad] || CryptoJS.pad.Pkcs7;
  
  // 执行解密
  const decrypted = CryptoJS.AES.decrypt(encryptedData, keyHex, {
    mode: cryptMode,
    padding: cryptPadding
  });
  
  return decrypted.toString(CryptoJS.enc.Utf8);
}

/**
 * MD5哈希加密（不可逆）
 * @param data 待加密数据
 * @returns MD5哈希值
 */
export function md5Encrypt(data: string): string {
  return CryptoJS.MD5(data).toString();
}

/**
 * 加密登录请求数据
 * 实现文档中描述的加密流程：
 * 1. 生成随机AES密钥
 * 2. 使用RSA公钥加密AES密钥
 * 3. 使用AES密钥加密请求数据
 * 
 * @param loginData 登录数据对象
 * @returns 加密后的数据和请求头
 */
export function encryptLoginData(loginData: any): {
  data: string;
  headers: {
    isEncrypt: boolean;
    encryptKey: string;
  }
} {
  // 1. 生成随机AES密钥
  const aesKey = generateAesKey();
  
  // 2. 使用RSA公钥加密AES密钥
  const encryptedKey = encryptWithRsa(encryptBase64(aesKey));
  
  // 3. 使用AES加密数据
  const jsonStr = JSON.stringify(loginData);
  const encryptedData = encryptWithAes(jsonStr, aesKey);
  
  // 将加密后的数据进行Base64编码，确保特殊字符不会影响传输
  const encodedData = encryptBase64(encryptedData);
  
  return {
    data: encodedData,
    headers: {
      isEncrypt: true,
      encryptKey: encryptedKey
    }
  };
} 